package com.hxh.rpc.provider;

import com.hxh.rpc.model.RpcRequest;
import com.hxh.rpc.model.RpcResponse;
import com.hxh.rpc.util.ServiceUtils;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.reflect.FastClass;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * Rpc实际请求处理逻辑，接收请求参数，返回RPC响应结果
 *
 * @author hxh
 * @date 2022/3/2
 * @since 1.0
 */
@Slf4j
public class RpcProviderNettyHandler extends SimpleChannelInboundHandler<RpcRequest> {
    /**
     * 提供rpc服务实例缓存
     */
    private Map<String, Object> handlerMap;

    public RpcProviderNettyHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception {
        RpcProviderBean.submit(() -> {
            String bizNo = rpcRequest.getBizNo();
            log.debug("receive rpc request:{}", bizNo);
            RpcResponse rpcResponse = new RpcResponse();
            rpcResponse.setBizNo(bizNo);
            Object data = null;
            try {
                data = doHandle(rpcRequest);
            } catch (InvocationTargetException e) {
                rpcResponse.setMessage(e.getMessage());
                log.error("handle rpcRequest error", e);
            }
            rpcResponse.setData(data);
            ctx.writeAndFlush(rpcResponse).addListener((ChannelFutureListener) channelFuture -> log.info("request: {}, response:{}", rpcRequest, rpcResponse));
        });

    }

    private Object doHandle(RpcRequest rpcRequest) throws InvocationTargetException {
        String key = ServiceUtils.buildServiceKey(rpcRequest.getClassName(), rpcRequest.getServiceVersion());
        if (handlerMap == null || handlerMap.get(key) == null) {
            log.error("the provider {} not exists", key);
            throw new RuntimeException("the provider not exists");
        }
        log.info("[initData] rpcRequest: {}", rpcRequest);
        Object provider = handlerMap.get(key);
        //动态代理调用远程服务方法
        FastClass fastClass = FastClass.create(provider.getClass());
        return fastClass.invoke(fastClass.getIndex(rpcRequest.getMethodName(), rpcRequest.getParamTypes()), provider, rpcRequest.getParamTypes());
    }
}
